home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / HippoDraw / HippoDrawSrc1.1 / Hippo.subproj / HGraphicView.m < prev    next >
Encoding:
Text File  |  1992-04-25  |  23.9 KB  |  974 lines

  1. /* Hippo Graphic View    by Paul Kunz    June 1991
  2.  * a subclass of GraphicView in /NextDeveloper/Examples/Draw
  3.  * to add or over-ride so that it can handle hippo Graphic objects
  4.  *
  5.  * Copyright (C)  1991  The Board of Trustees of
  6.  * The Leland Stanford Junior University.  All Rights Reserved.
  7.  */
  8.  
  9. #import "HGraphicView.h"
  10.  
  11. const char HGraphicView_h_rcsid[] = HGRAPHICVIEW_H_ID;
  12. const char HGraphicView_m_rcsid[] = "$Id: HGraphicView.m,v 1.73 1992/04/25 18:56:24 pfkeb Rel $";
  13.  
  14. #import <appkit/Application.h>
  15. #import <appkit/Form.h>
  16. #import <appkit/Matrix.h>
  17. #import <appkit/MenuCell.h>
  18. #import <appkit/OpenPanel.h>
  19. #import <appkit/Pasteboard.h>
  20. #import <objc/List.h>
  21. #import "Rectangle.h"
  22.  
  23. #import "DrawDocument.h"
  24. #import "HDraw.h"
  25. #import "HTuple.h"
  26. #import "InspectCut.h"
  27. #import "InspectPlot.h"
  28. #import "InspectTuple.h"
  29. #import "NewInspector.h"
  30. #import "Plot.h"
  31. #import "Graphic.h"
  32. #import "Overlay.h"
  33. #import "PageMarker.h"
  34. #import <appkit/nextstd.h>
  35. #import <defaults.h>
  36. #import <stdlib.h>
  37. #import <mach.h>
  38. #import <zone.h>
  39.  
  40. #define DIRTY(condition) \
  41.     if (condition && !gvFlags.dirty) { \
  42.     gvFlags.dirty = YES; \
  43.     [window setDocEdited:YES]; \
  44.     }  
  45.       
  46. #define DEF_PLOT_SIZE 260.0
  47.  
  48. @implementation HGraphicView : GraphicView
  49.  
  50. static id currentGraphic = nil;    /* won't be used if NXApp knows how
  51.                    to keep track of the currentGraphic */
  52.  
  53. + initialize
  54. {
  55.     static NXDefaultsVector HippoDrawDefaults = {
  56.     { "NumPlotCols", "2" },
  57.     { "NumPlotRows", "3" },
  58.     { NULL, NULL }
  59.     };
  60.     [self setVersion:[[self superClass] version]];
  61.     NXRegisterDefaults("HippoDraw", HippoDrawDefaults);
  62.     return self;
  63. }
  64. + convert:(NXTypedStream *)ts to:(const char *)type using:(SEL)writer toPasteboard:pb
  65. /*
  66.  * Over ride this method in order to make scrapper a HGraphicView
  67.  */
  68. {
  69.     id w;
  70.     char *data;
  71.     NXZone *zone;
  72.     NXStream *stream;
  73.     int length, maxlen;
  74.     HGraphicView *scrapper;
  75.     NXRect origFrame;
  76.     NXPoint movePoint;
  77.     const NXRect scrapperFrame = {{0.0, 0.0}, {11.0*72.0, 14.0*72.0}};
  78.  
  79.     if (!ts) return self;
  80.  
  81.     zone = NXCreateZone(vm_page_size, vm_page_size, NO);
  82.     NXNameZone(zone, "Scrapper");
  83.     scrapper = [[HGraphicView allocFromZone:zone] initFrame:&scrapperFrame];
  84.     w = [[Window allocFromZone:zone] initContent:&scrapperFrame
  85.                        style:NX_PLAINSTYLE
  86.                      backing:NX_NONRETAINED
  87.                       buttonMask:0
  88.                        defer:NO];
  89.     [w reenableDisplay];
  90.     [w setContentView:scrapper];
  91.  
  92.     stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  93.     NXSetTypedStreamZone(ts, zone);
  94.     scrapper->glist = NXReadObject(ts);
  95.  /* move graphics onto page */
  96.     [scrapper getBBox:&origFrame of:scrapper->glist extended:NO];
  97.     movePoint.x = - origFrame.origin.x;
  98.     movePoint.y = - origFrame.origin.y;
  99.     [scrapper selectAll:self];
  100.     [scrapper graphicsPerform:@selector(moveBy:)
  101.                         with:(id)&movePoint andDraw:NO];
  102.     [scrapper deselectAll:self];
  103.     [scrapper perform:writer with:(id)stream];
  104.     NXGetMemoryBuffer(stream, &data, &length, &maxlen);
  105.     [pb writeType:type data:data length:length];
  106.     NXCloseMemory(stream, NX_FREEBUFFER);
  107.     [w free];
  108.     NXDestroyZone(zone);
  109.  
  110.     return self;
  111. }
  112. - initFrame:(const NXRect *)frameRect
  113. {
  114.     [super initFrame:frameRect];
  115.     hDraw = NXGetNamedObject("HDrawInstance", NXApp);
  116.     return self;
  117. }
  118.  
  119. - (BOOL)validateCommand:menuCell
  120. {
  121.     id            g;
  122.     SEL            action;
  123.     unsigned int    i, count, pcount;
  124.     BOOL        retval;
  125.     
  126.     retval = [super validateCommand:menuCell];
  127.     if ( retval == NO ) {
  128.         return NO;
  129.     }
  130.     action = [menuCell action];
  131.     if ( action == @selector(overlay:) ||
  132.          action == @selector(alignXRange:) ||
  133.      action == @selector(alignXNumBins:) ||
  134.      action == @selector(alignYRange:) ||
  135.      action == @selector(alignYNumBins:) ) {
  136.     count = [slist count]; 
  137.         if ( !count ) {
  138.         return NO;
  139.     }
  140.     pcount = 0;
  141.     for ( i = 0; i < count; i ++ ) {
  142.         g = [slist objectAt:i];
  143.         if ( [g isKindOf:[Plot class]] ) {
  144.             pcount++;
  145.         }
  146.     }
  147.     if ( pcount < 2 ) {
  148.         return NO;
  149.     }
  150.     }
  151.     if ( action == @selector(unoverlay:) ) {
  152.         count = [slist count];
  153.     if ( !count ) {
  154.         return NO;
  155.     }
  156.     for ( i = 0; i < count; i++ ) {
  157.         g = [slist objectAt:i];
  158.         if ( [g isKindOf:[Overlay class]] ) {
  159.             return YES;
  160.         }
  161.     }
  162.     return NO;
  163.     }
  164.     return YES;
  165. }
  166. - delete:sender
  167. {
  168.     if ( [self isAllowed] ) {
  169.         return [super delete:sender];
  170.     }
  171.     return self;
  172. }
  173. - cut:sender
  174. {
  175.     if ( [self isAllowed] ) {
  176.         return [super cut:sender];
  177.     }
  178.     return self;
  179. }
  180. - (BOOL) isAllowed
  181. {
  182.     id        inspectCut;
  183.     id        g;
  184.     int        i, irc;
  185.     
  186.     i = [slist count];
  187.     while (i-- ) {
  188.         g = [slist objectAt:i];
  189.         if ( [g isKindOf:[Plot class]] ) {
  190.         if ( [g isCutHist] ) {
  191.             if ( [g dependCount] ) {
  192.             irc = NXRunAlertPanel("Can not delete",
  193.                   "Selected graphic include plots that display"
  194.                   " a cut.  Remove cut from target plot(s) first.",
  195.                   "OK", NULL, NULL);
  196.             return NO;
  197.         }
  198.         inspectCut = [hDraw inspectCut];
  199.         [inspectCut deleteCut:g];
  200.         }
  201.         if ( [g hasCut] ) {
  202.             [g removeAllCuts];
  203.         }
  204.     }
  205.     }
  206.     return YES;
  207. }
  208. - setTuple:(ntuple) nt withNewDisplay:(int) dim
  209. {
  210.     graphtype_t        type;
  211.  
  212.     type = (dim==1) ? HISTOGRAM : COLORPLOT;
  213.     [self addPlotOfType:type andSelect:YES];
  214.     return self;
  215. }
  216. - addPlotOfType:(int) type
  217. {
  218.     return [self addPlotOfType:type andSelect:YES];
  219. }
  220. - addPlotOfType:(int) type andSelect:(BOOL) selFlag
  221. {
  222.     id            theInspector;
  223.     id            inspectTuple;
  224.     id            plot, htuple;
  225.     display        disp;
  226.     func_id        cutfunc;
  227.     NXRect        bbox;
  228.     int            index;
  229.     
  230.     currentGraphic = nil;
  231.     [hDraw setCurrentGraphic:nil];
  232.     inspectTuple = [hDraw inspectTuple];
  233.     htuple = [inspectTuple currentHTuple];
  234.     if ( !htuple ) {
  235.         return self;
  236.     }
  237.     if ( (type != HISTOGRAM) && (h_getNtDim([htuple ntuple]) <= 1 ) ) {
  238.         return self;
  239.     }
  240.     plot = [inspectTuple firstPlot];
  241.     if ( plot ) {
  242.         disp = [plot histDisplay];
  243.     if ( type == h_getDispType(disp) ) {
  244.         disp = h_copyDisp(disp);
  245.         while ( (cutfunc = h_nextCut(disp, NULL)) ) {
  246.             h_deleteCut(disp, cutfunc);
  247.         }
  248.     } else {
  249.         h_getDrawRect( disp, (rectangle *)&bbox );
  250.             disp = h_newDisp(type);
  251.         h_setDrawRect(disp, (rectangle *) &bbox);
  252.     }
  253.     } else {
  254.     disp = h_newDisp(type);
  255.         [self calcDefaultPlotSize:&bbox];
  256.     h_setDrawRect(disp, (rectangle *) &bbox);
  257.     }
  258.     
  259.     plot = [[Plot allocFromZone:[self zone]] init];
  260.     [plot setGraphicView:self];
  261.     [plot setHTuple:htuple withDisplay:disp ];
  262.     
  263.     index = h_getBinding( disp, XAXIS );
  264.     [plot bindAxisX:&index];
  265.     if ( h_getDispType(disp) != HISTOGRAM ) {
  266.         index = h_getBinding( disp, YAXIS );
  267.     [plot bindAxisY:&index];
  268.     }
  269.     
  270.     [plot setCutHistFlag: NO];
  271.     if ( selFlag ) {
  272.         [ self deselectAll:self];
  273.     }
  274.     [self placeDisplay: plot select:selFlag];
  275.     [plot getBounds: &bbox ];
  276.     [self scrollRectToVisible: &bbox];
  277.     [window makeKeyWindow];
  278.     if ( selFlag ) {
  279.     [NXApp updateWindows]; 
  280.     theInspector = [hDraw newInspector];
  281.     [theInspector show:"Data Selection"];
  282.     [theInspector orderFrontPanel:self];
  283.     }
  284.     return plot;
  285. }
  286. - hTupleForFile:(const char *)filename index:(int) iValue
  287. {
  288.     id        inspectTuple;
  289.     
  290.     inspectTuple = [hDraw inspectTuple];
  291.     return [inspectTuple hTupleForFile:filename index:iValue];
  292. }
  293. - addCut:plot
  294. {
  295.     id    inspectCut;
  296.     
  297.     inspectCut = [hDraw inspectCut];
  298.     [inspectCut addCut:plot];
  299.     return self;
  300. }
  301. - placeDisplay:(id) plot select: (int) sel
  302. {
  303.      NXRect    curRect, resizeRect;
  304.      NXRect    frameRect, box;
  305.      NXRect    sliceRect, filledRect;
  306.      float    pageHeight;
  307.      id     g, myglist;
  308.      int     below=1, i;
  309.      
  310.      /* resize the view and move every thing up to accomodate new Plot */
  311.      [ plot getBounds:&resizeRect ];
  312.      [ self getFrame: &frameRect ];
  313.  
  314.      myglist = [[List allocFromZone:[self zone]] init];
  315.      for (i=[glist count]-1; i>=0; i--)
  316.      {
  317.       g = [glist objectAt:i];
  318.       if (![g isLocked]) [myglist insertObject:g at:0];
  319.      }
  320.      [ self getBBox:&curRect of:myglist ];
  321.      
  322.      /*
  323.       * when there is nothing in the plot, bounding box comes back with 
  324.       *  all 0's. Reset to region at top of page.
  325.       */
  326.     if ( NXEmptyRect(&curRect) )  {
  327.         curRect.origin.x = 5.0;
  328.     curRect.origin.y = frameRect.size.height - 5.0;
  329.     } else if (curRect.size.height >= resizeRect.size.height) {
  330.       /*
  331.        * see if there is room on right at bottom of bounding box.
  332.        */
  333.       NXDivideRect( &curRect, &sliceRect, NX_HEIGHT(&resizeRect), 1 );
  334.       NXSetRect( &filledRect, 0.0, 0.0, 0.0, 0.0 );
  335.       i = [myglist count];
  336.       while ( i-- ) {
  337.           g = [myglist objectAt:i];
  338.           [g getBounds:&box];
  339.           NXIntersectionRect( &sliceRect, &box );
  340.           NXUnionRect( &box, &filledRect );
  341.       }
  342.       resizeRect.origin.x = NX_WIDTH(&filledRect)+10.0;
  343.       resizeRect.origin.y = NX_Y(&filledRect);
  344.       below = ( (NX_MAXX(&resizeRect) + 5.0) > NX_WIDTH(&frameRect) );
  345.       NXUnionRect( &sliceRect, &curRect );
  346.      }
  347.  
  348.     [[[self window] delegate] getPageFrame:&box];
  349.     pageHeight = box.size.height;
  350.      if (below) {
  351.       if ((curRect.origin.y-frameRect.origin.y) < resizeRect.size.height)
  352.       {
  353.            [ self addPage:self ];
  354.            /* 
  355.         * everything was moved up by 1 page, so change the current
  356.         * bounding box.
  357.         */
  358.            curRect.origin.y +=pageHeight;
  359.       }
  360.       resizeRect.origin.x = 5.0;
  361.       resizeRect.origin.y = curRect.origin.y - resizeRect.size.height;
  362.      }
  363.  
  364.      /*
  365.       * make sure plot does not cross page boundary.
  366.       */
  367.      if ((int)(resizeRect.origin.y/pageHeight) !=
  368.      (int)((resizeRect.origin.y+resizeRect.size.height)/pageHeight) ) {
  369.       resizeRect.origin.y = pageHeight*
  370.                             (int)(resizeRect.origin.y/pageHeight + 1) - 
  371.                         resizeRect.size.height - 5.0;
  372.      }
  373.      NXIntegralRect( &resizeRect );
  374.      [ plot setBounds: &resizeRect ];
  375.  
  376.      if (sel) {
  377.       [ self insertGraphic: plot];
  378.      } else {
  379.       [ self insertGraphicNoSelect: plot];
  380.           [self recacheSelection];
  381.      }
  382.  
  383.      [myglist free];
  384.      return self;
  385. }
  386.  
  387. - addPage:sender
  388. {
  389.      NXRect     box;
  390.      int i;
  391.      id g;
  392.           
  393.      /*
  394.       * add a page marker 
  395.       * it is inserted at the very top of the document.
  396.       */
  397.      [self notifyAncestorWhenFrameChanged:YES];
  398.      [[[PageMarker new] init] addSelf: self];
  399.  
  400.      /*
  401.       * add page. It gets add to TOP of document, so move everything up
  402.       */
  403.      [[[self window] delegate] getPageFrame:&box];
  404.      box.size.width = 0.0;
  405.      [ self sizeBy:box.size.width : box.size.height ];
  406.  
  407.      for (i=[glist count]-1; i>=0; i--)
  408.      {
  409.       g = [glist objectAt:i];
  410.       if (![g isLocked]) [g moveBy: (const NXPoint *) &box.size];
  411.      }
  412.  
  413.      [ self getFrame:&box ];
  414.      [self cache:&box ];
  415.      [window flushWindow];
  416.  
  417.      return self;
  418. }
  419.  
  420.  
  421. - saveAsExportFile:(const char *)filename
  422. {
  423.     id        inspectTuple;
  424.     id        htuple;
  425.     ntuple    nt;
  426.     display    disp;
  427.     const char    *ntFilename;
  428.     int        i, irc;
  429.     BOOL    refFlag;
  430.     
  431.     dispList = [self displayList];
  432.     if ( dispList == NULL ) {
  433.         return self;
  434.     }
  435.     inspectTuple = [hDraw inspectTuple];
  436.     
  437.  /* update the ntuple filename for referenced tuples before saving */
  438.     for ( i = 0; (disp = dispList[i]) != NULL; i++) {
  439.         nt = h_getNtuple( disp );
  440.     htuple = [inspectTuple hTupleForTuple:nt];
  441.     refFlag = [htuple isRef];
  442.     ntFilename = [htuple filename];
  443.     h_setNtByRef( disp, refFlag, ntFilename );
  444.     }
  445.     if ( h_write( filename, dispList, NULL ) ) {
  446.     irc = NXRunAlertPanel("Alert", "Couldn't save export file",
  447.                 "OK", NULL, NULL);
  448.     }
  449.     return self;
  450. }
  451. - (display *) displayList;
  452. {
  453.     id        g;
  454.     int        i, count, num_disp;
  455.     
  456.     plotList = [self plotList];
  457.     count = [plotList count];
  458.     if ( dispList != NULL ) {
  459.     NX_ZONEREALLOC( [self zone], dispList, display, count+1 );
  460.     } else {
  461.         NX_ZONEMALLOC( [self zone], dispList, display, count+1 );
  462.     }
  463.     num_disp = 0;
  464.     for ( i = 0; i < count; i ++ ) {
  465.         g = [plotList objectAt:i];
  466.     dispList[num_disp++] = [g histDisplay];
  467.     }
  468.     dispList[num_disp] = NULL;
  469.     return dispList;
  470. }
  471. - plotList
  472. {
  473.     if ( !plotList ) {
  474.         plotList = [[List allocFromZone:[self zone]] initCount:0];
  475.     } else {
  476.         [plotList empty];
  477.     }
  478.     [glist makeObjectsPerform:@selector(addPlotToList:) with:plotList];
  479.     return plotList;
  480. }
  481. - cutList
  482. {
  483.     if ( !cutList ) {
  484.         cutList = [[List allocFromZone:[self zone]] initCount:0];
  485.     }
  486.     return cutList;
  487. }
  488. - firstPlot
  489. {
  490.     id        g;
  491.     
  492.     if ([slist count] == 1) {
  493.     g = [slist objectAt:0];
  494.     if ( [g isKindOf:[Overlay class]] ) {
  495.         return [g firstPlot];
  496.     }
  497.     if ( [ g isKindOf:[Plot class]] ) {
  498.         return g;
  499.     }
  500.     }
  501.     return nil;
  502. }
  503.  
  504.  
  505. - reDrawPlot
  506. {
  507.     [self selectAll:self];
  508.     [self deselectAll:self];
  509.     [window flushWindow];
  510.  
  511.     return self;
  512. }
  513. - graphicsPerformNOP: g
  514. {
  515.     NXRect              affectedBounds;
  516.  
  517.     [g getExtendedBounds:&affectedBounds];
  518.     [self cache:&affectedBounds];
  519.  
  520.     return self;
  521. }
  522. - graphicsPerform:(SEL)aSelector with:(void *)argument
  523.                    andDraw:(BOOL)flag inList:aList
  524. {
  525.     id        savesList;
  526.     
  527.     savesList = slist;
  528.     slist = aList;
  529.     [self graphicsPerform:aSelector with:argument andDraw:flag];
  530.     slist = savesList;
  531.     return self;
  532. }
  533. - graphicsPerform:(SEL)aSelector with:arg1 with:arg2
  534. {
  535.     id        g;
  536.     unsigned    i, count;
  537.     
  538.     count = [slist count];
  539.     for ( i = 0; i < count; i++ ) {
  540.         g = [slist objectAt:i];
  541.     [g perform:aSelector with:arg1 with:arg2];
  542.     }
  543.     return self;
  544. }
  545.  
  546. - currentGraphic
  547. {
  548.     return [hDraw currentGraphic];
  549. }
  550. - alignAll:sender
  551. {
  552.  // This method is obsolete and kept in the 1.1 release for
  553.  // backward compatability.
  554.     return [self overlay:sender];
  555. }
  556. - alignSize:sender
  557. {
  558.  // backward compatible code.   Remove in next release
  559.     return [self overlay:sender];
  560. }
  561. - overlay:sender
  562. /*
  563.  * Creates a new Group object with the current slist as its member list.
  564.  * See the Group class for more info.
  565.  */
  566. {
  567.     id        g, plotInsp, firstPlot;
  568.     NXRect    eb;
  569.     graphtype_t    firstType, plotType;
  570.     int        i, irc;
  571.  
  572.     plotInsp = [hDraw inspectPlot];
  573.     if ( plotInsp == nil ) return self;
  574.     firstPlot = [plotInsp firstPlot];
  575.     
  576.  /* If firstPlot is nil, which can happen if user just did a unoverlay,
  577.   * then pick a plot in the list to be the firstPlot.
  578.   */
  579.     if ( firstPlot == nil ) {
  580.         i = [slist count];
  581.     while( i-- ) {
  582.         g = [slist objectAt:i];
  583.         if ( [g isKindOf:[Plot class]] ) {
  584.             firstPlot = g;
  585.         break;
  586.         }
  587.     }
  588.     }
  589.     
  590.  /* See if all Plots are of same type */
  591.     [firstPlot getDispType:&firstType];
  592.     i = [slist count];
  593.     while( i-- ) {
  594.         g = [slist objectAt:i];
  595.     if ( [g isKindOf:[Plot class]] ) {
  596.         [g getDispType:&plotType];
  597.         if ( plotType != firstType ) {
  598.         irc = NXRunAlertPanel("Alert",
  599.             "Overlaying Plots of different types not allowed",
  600.             "OK", NULL, NULL);
  601.         return self;
  602.         }
  603.     }
  604.     }
  605.     i = [slist count];
  606.     if (i > 1) {
  607.     DIRTY(YES);
  608.     while (i--) [glist removeObject:[slist objectAt:i]];
  609.     g = [[Overlay allocFromZone:[self zone]] initList:slist
  610.                          with:firstPlot];
  611.     [glist insertObject:g at:0];
  612.     slist = [[List allocFromZone:[self zone]] init];
  613.     [slist addObject:g];
  614.     gvFlags.groupInSlist = YES;
  615.     [self cache:[g getInitialBounds:&eb]];
  616.     if (sender != self) [window flushWindow];
  617.     }
  618.     [ window flushWindow];
  619.     return self;
  620. }
  621. - unoverlay:sender
  622. /*
  623.  * Goes through the slist and ungroups any Group objects in it.
  624.  * Does not descend any further than that (i.e. all the Group objects
  625.  * in the slist are ungrouped, but any Group objects in those ungrouped
  626.  * objects are NOT ungrouped).
  627.  */
  628. {
  629.     id    g, tlist;
  630.     int i, j, k;
  631.     NXRect sbounds, tbounds;
  632.     BOOL found = NO;
  633.  
  634.     [self getBBox:&sbounds of:slist];
  635.     i = [slist count];
  636.     while (i--) {
  637.     g = [slist objectAt:i];
  638.     if ([g isKindOf:[Overlay class]]) {
  639.         k = [glist indexOf:g];
  640.         [glist removeObjectAt:k];
  641.         found = YES;
  642.         tlist = [[List allocFromZone:[self zone]] initCount:0];
  643.         [[g transferSubGraphicsTo:tlist at:0] free];
  644.         [self getBBox:&tbounds of:tlist];
  645.         NXUnionRect( &tbounds, &sbounds );
  646.         j = [tlist count];
  647.         while ( j-- ) {
  648.             g = [tlist objectAt:j];
  649.         [glist insertObject:g at:k];
  650.         }
  651.         [tlist free];
  652.     }
  653.     }
  654.  
  655.     if (found) {
  656.     DIRTY(YES);
  657.     [self cache:&sbounds];
  658.     if (sender != self) [window flushWindow];
  659.     [self getSelection];
  660.     }
  661.  
  662.     return self;
  663. }
  664.  
  665. - alignXRange:sender
  666. {
  667.     id        plotInsp, firstPlot;
  668.     NXPoint    theRange;
  669.     
  670.     plotInsp = [hDraw inspectPlot];
  671.     if ( plotInsp == nil ) return self;
  672.     firstPlot = [plotInsp firstPlot];
  673.     if ( firstPlot == nil ) return self;
  674.     [firstPlot getRangeForAxisX:&theRange];
  675.     [ self graphicsPerform:@selector(setRangeForAxisX:)
  676.         with: (id)&theRange andDraw:YES ];
  677.     [ window flushWindow];
  678.     return self;
  679. }
  680. - alignYRange:sender
  681. {
  682.     id        plotInsp, firstPlot;
  683.     NXPoint    theRange;
  684.     
  685.     plotInsp = [hDraw inspectPlot];
  686.     if ( plotInsp == nil ) return self;
  687.     firstPlot = [plotInsp firstPlot];
  688.     if ( firstPlot == nil ) return self;
  689.     [firstPlot getRangeForAxisY:&theRange];
  690.     [ self graphicsPerform:@selector(setRangeForAxisY:)
  691.         with: (id)&theRange andDraw:YES ];
  692.     [ window flushWindow];
  693.     return self;
  694. }
  695. - alignXNumBins:sender
  696. {
  697.     id        plotInsp, firstPlot;
  698.     int        numBins;
  699.     
  700.     plotInsp = [hDraw inspectPlot];
  701.     if ( plotInsp == nil ) return self;
  702.     firstPlot = [plotInsp firstPlot];
  703.     if ( firstPlot == nil ) return self;
  704.     numBins = [firstPlot numBinsForAxis: XAXIS ];
  705.     [ self graphicsPerform:@selector(setNumBinsForAxisX:)
  706.         with: (id)&numBins andDraw:YES ];
  707.     [ window flushWindow];
  708.     return self;
  709. }
  710. - alignYNumBins:sender
  711. {
  712.     id        plotInsp, firstPlot;
  713.     int            numBins;
  714.     graphtype_t gt;
  715.     
  716.     plotInsp = [hDraw inspectPlot];
  717.     if ( plotInsp == nil ) return self;
  718.     firstPlot = [plotInsp firstPlot];
  719.     if ( firstPlot == nil ) return self;
  720.     [firstPlot getDispType: >];
  721.     if ( gt == HISTOGRAM ) return self;
  722.     numBins = [firstPlot numBinsForAxis: YAXIS ];
  723.     [ self graphicsPerform:@selector(setNumBinsForAxisY:)
  724.         with: (id)&numBins andDraw:YES ];
  725.     [ window flushWindow];
  726.     return self;
  727. }
  728. - copyPSToPasteboard:pboard
  729. {
  730.     char *data;
  731.     NXStream *stream;   
  732.     const char *types[1];
  733.     int length, maxlen;
  734.  
  735.     if ([slist count]) {
  736.     types[0] = NXPostScriptPboardType;
  737.     stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  738.     [ self copySelectionAsPS:stream];
  739.     NXGetMemoryBuffer(stream, &data, &length, &maxlen);
  740.     [pboard declareTypes:types num:1 owner:[self class]];
  741.     [pboard writeType:NXPostScriptPboardType data:data length:length];
  742.     NXCloseMemory(stream, NX_FREEBUFFER);
  743.     return self;
  744.     } else {
  745.     return nil;
  746.     }
  747. }
  748. - pasteFromPasteboard:pboard
  749. {
  750.     id        pblist;
  751.     NXRect    bbox;
  752.     
  753.     pblist = [ super pasteFromPasteboard:pboard ];
  754.     if ( !pblist ) return nil;
  755.     [self getBBox:&bbox of:pblist extended:NO];
  756.     if ( !NXContainsRect( &bounds, &bbox ) ) {
  757.         if ( NX_MAXX(&bbox) > NX_WIDTH(&bounds) ) {
  758.         bbox.origin.x = -( (bbox.origin.x + bbox.size.width) 
  759.                        - bounds.size.width);
  760.     }
  761.     if ( NX_MAXY(&bbox) > NX_HEIGHT(&bounds) ) {
  762.         bbox.origin.y = -( (bbox.origin.y + bbox.size.height)
  763.                         - bounds.size.height) -5.0;
  764.     }
  765.     [pblist makeObjectsPerform:@selector(moveBy:) with:(id)&bbox];
  766.     }
  767.     [ self bindDisplaysInList:pblist];
  768.     return pblist;
  769. }
  770. - writePSToStream:(NXStream *)stream
  771.  /* over-ride GraphicView method to add one line */
  772. {
  773.     NXRect bbox;
  774.  
  775.     if (stream) {
  776.     [self getBBox:&bbox of:glist];
  777.     [self bindDisplaysInList:glist]; /* Added line */
  778.     [self copyPSCodeInside:&bbox to:stream];
  779.     }
  780.  
  781.     return self;
  782. }
  783. - bindDisplays
  784. {
  785.     [ self bindDisplaysInList:glist];
  786.     return self;
  787. }
  788. - bindDisplaysInList:list
  789. {
  790.     [list makeObjectsPerform:@selector(setGraphicView:) with:self];
  791.     [list makeObjectsPerform:@selector(bindReference)];
  792.     [list makeObjectsPerform:@selector(bindCuts)];
  793.     return self;
  794. }
  795. - tupleList
  796. {
  797.     if ( !tupleList ) {
  798.         tupleList = [[List allocFromZone:[self zone]] initCount:0];
  799.     } else {
  800.         [tupleList empty];
  801.     }
  802.     [glist makeObjectsPerform:@selector(addHTupleToList:) with:tupleList];
  803.     return tupleList;
  804. }
  805. - replace:oldTuple with:newTuple
  806. {
  807.     id            g;
  808.     unsigned int    i;
  809.     
  810.     i = [glist count];
  811.     while ( i-- ) {
  812.         g = [glist objectAt:i];
  813.     [g replace:oldTuple with:newTuple];
  814.     }
  815.     return self;
  816. }
  817. - closeTupleFile:(const char *) filename
  818. {
  819.     id        inspectTuple;
  820.     id        htuple, plot;
  821.     int        i, j, pcount;
  822.     
  823.     plotList = [self plotList];
  824.     pcount = [plotList count];
  825.     if ( !pcount ) {
  826.         return self;
  827.     }
  828.     inspectTuple = [hDraw inspectTuple];
  829.     tupleList = [inspectTuple tupleListForFile:filename];
  830.     if ( ![tupleList count] ) {
  831.         return self;
  832.     }
  833.     for ( i = 0; i < pcount; i++) {
  834.         plot = [plotList objectAt:i];
  835.     htuple = [plot hTuple];
  836.     j = [tupleList indexOf:htuple];
  837.     if ( j != NX_NOT_IN_LIST ) {
  838.         [ plot closeTuple ];
  839.         }
  840.     }
  841.     return self;
  842. }
  843.            
  844. - openTuple:pasteBoard
  845.     userData:(const char *)args
  846.     error:(char **)errorMsg
  847. {
  848.     id        inspectTuple;
  849.     id        retval;
  850.     int         graphtype;
  851.  
  852.     inspectTuple = [hDraw inspectTuple];
  853.     retval = [inspectTuple openTuple:pasteBoard
  854.                            userData:args
  855.                error:errorMsg];
  856.     if ( retval == nil ) {
  857.         return self;
  858.     }
  859.     sscanf(args, "%i", &graphtype );
  860.     [self addPlotOfType:graphtype];
  861.     return self;
  862. }
  863. - calcDefaultPlotSize:(NXRect *) bbox
  864. {
  865.     NXRect        frameRect;
  866.     const char        *defaultValue;
  867.     unsigned int    cols, rows;
  868.     float        h, w;
  869.     
  870.     defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotCols" );
  871.     sscanf( defaultValue, "%u", &cols );
  872.     defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotRows" );
  873.     sscanf( defaultValue, "%u", &rows );
  874.     [[[self window] delegate] getPageFrame:&frameRect];
  875.     if ( NX_HEIGHT(&frameRect) > NX_WIDTH(&frameRect) ) {
  876.     w = (NX_WIDTH(&frameRect) - 5.0*cols)/cols - 5.0;
  877.     h = (NX_HEIGHT(&frameRect) - 5.0*rows)/ rows - 5.0;
  878.     } else {
  879.     w = (NX_WIDTH(&frameRect) - 5.0*rows)/rows - 5.0;
  880.     h = (NX_HEIGHT(&frameRect) - 5.0*cols)/cols - 5.0;
  881.     }
  882.     NXSetRect( bbox, 0, 0, w, h );
  883.     return self;
  884. }
  885. - prefPanel:sender
  886. {
  887.     const char    *defaultValue;
  888.     
  889.     if( ! prefPanel ){
  890.         [NXApp loadNibSection:"HGraphicView.nib" owner:self
  891.                withNames:NO fromZone:[self zone]];
  892.     }
  893.     defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotCols" );
  894.     [prefForm setStringValue:defaultValue at:0];
  895.     defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotRows" );
  896.     [prefForm setStringValue:defaultValue at:1];
  897.     [prefPanel makeKeyAndOrderFront:sender];
  898.     return self;    
  899. }
  900. - prefButton:sender
  901. {
  902.     char    string[80];
  903.     int        cols, rows;
  904.     
  905.     [prefPanel orderOut:self];
  906.     if ( [sender selectedCol] == 1 ) {
  907.         cols = [prefForm intValueAt:0];
  908.     rows = [prefForm intValueAt:1];
  909.     sprintf( string, "%u", cols );
  910.     NXWriteDefault("HippoDraw", "NumPlotCols", string );
  911.     sprintf( string, "%u", rows );
  912.     NXWriteDefault("HippoDraw", "NumPlotRows", string );
  913.     [self deselectAll:self];
  914.     [window flushWindow];
  915.     }
  916.     NXUpdateDefaults();
  917.     return self;
  918. }
  919. - write:(NXTypedStream *)stream
  920. {
  921.     id            cut;
  922.     unsigned int    i, count;
  923.     
  924.     [super write:stream];
  925.     tupleList = [self tupleList];
  926.     NXWriteObject( stream, tupleList );
  927.     if ( cutList ) {
  928.         count = [cutList count];
  929.     } else {
  930.         count = 0;
  931.     }
  932.     NXWriteType( stream, "i", &count );
  933.     for ( i = 0; i < count; i++ ) {
  934.         cut = [cutList objectAt:i];
  935.     NXWriteObjectReference( stream, cut );
  936.     }
  937.     return self;
  938. }
  939. - read:(NXTypedStream *)stream
  940. {
  941.     id            cut;
  942.     unsigned int    i, count;
  943.     
  944.     [super read:stream];
  945.     
  946.     tupleList = NXReadObject( stream );
  947.     NXReadType( stream, "i", &count );
  948.     if ( count ) {
  949.         cutList = [[List allocFromZone:[self zone]] initCount:0];
  950.     }
  951.     for ( i = 0; i < count; i++ ) {
  952.         cut = NXReadObject( stream );
  953.     if ( cut ) {
  954.         [cutList addObject:cut];
  955.     }
  956.     }
  957.     return self;
  958. }
  959. - awake
  960. {
  961.     id        inspectTuple;
  962.     
  963.     hDraw = NXGetNamedObject("HDrawInstance", NXApp);
  964.     if ( tupleList && [tupleList count] ) {
  965.     [ hDraw orderFrontTupleInsp:self];
  966.     inspectTuple = [hDraw inspectTuple];
  967.     [inspectTuple addTuplesIfAbsent:tupleList for:self];
  968.     [ tupleList empty];
  969.     }
  970.     [self bindDisplays];
  971.     return [super awake];
  972. }
  973. @end
  974.